home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Night Owl 6
/
Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso
/
019a
/
tde10src.zip
/
TDEASM.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-06-05
|
40KB
|
983 lines
/*
* I have decided to use ^Z to mark the begin and end of files instead of '\0'.
* That way, null characters are allowed as normal text characters. ^Z is used
* to mark the end of strings in buffers instead of '\0'. The standard C
* string library functions should not be used when dealing with text buffers.
*
* The often used string routines have been rewritten in assembly. When using
* 16 bit processors, accessing memory by WORDs on WORD boundaries is twice
* as fast as accessing memory by BYTEs. If a memory pointer is even then it
* is WORD aligned. If a memory pointer is odd, do the first BYTE and then
* the rest of the string is WORD aligned on an even boundary.
*
* Two routines were written to adjust the string pointers whenever they
* approach the end of a segment. With these two routines, the code may
* be compiled without the huge memory model. Another assembly routine was
* written to compare physical memory locations. For example, all of these
* pointers point to same physical memory address:
*
* 59a1:9122 == 58a1:a122 == 62a1:0122 = physical address 404,274
*
* An efficient way to compare far pointers is to convert them to either
* unsigned long or long integers. Either one will do - their is no such
* thing a negative physical memory address. A long int goes from
* -2 billion to 2 billion, which leaves plenty of room to describe a physical
* address, using a long, where the max is 1 MEG. I used unsigned long. When
* adding or subtracting from the physical address of a pointer, we should
* never, ever get a negative physical address. This is the concept behind the
* function ptoul, which is short for pointer to unsigned long.
*
* With these functions written in assembly, this editor is fairly fast. I
* feel the need for speed.
*
* New editor name: tde, the Thomson-Davis Editor.
* Author: Frank Davis
* Date: June 5, 1991
*
* This modification of Douglas Thomson's code is released into the
* public domain, Frank Davis. You may distribute it freely.
*/
#include "tdestr.h"
#include "common.h"
#include "tdefunc.h"
/*
* Name: cpf - check_pointer_foward
* Purpose: To adjust a pointer if it is nearing end of a segment (within 16k)
* Date: June 5, 1991
* Passed: s: string pointer
* Notes: To avoid a bunch of code generated for pointer arithmetic when using
* the huge memory model, this routine adjusts a pointer when it
* approaches the end of a segment.
*/
text_ptr cpf( s )
text_ptr s;
{
_asm {
mov ax, WORD PTR s ; get offset of s
mov dx, WORD PTR s+2 ; get segment of s
cmp ax, 0xc000 ; are we within 16k of top of segment?
jb get_out ; no, get out
sub ax, 0x8000 ; yes, subtract 32k from offset
add dx, 0x0800 ; add 0x0800 paragraphs to segment == 32k
get_out:
}
}
/*
* Name: cpb - check_pointer_backward
* Purpose: To adjust a pointer if it is nearing beginning of a segment (16k)
* Date: June 5, 1991
* Passed: s: string pointer
* Notes: To avoid a bunch of code generated for pointer arithmetic when using
* the huge memory model, this routine adjusts a pointer when it
* approaches the beginning of a segment. Don't check NULL pointer.
*/
text_ptr cpb( s )
text_ptr s;
{
_asm {
mov ax, WORD PTR s ; get offset of s
mov dx, WORD PTR s+2 ; get segment of s
cmp ax, 0 ; is offset of s == NULL?
jne not_null ; no, check pointer
cmp dx, 0 ; is segment of s == NULL?
je get_out ; yes, don't check NULL pointer
not_null:
cmp ax, 0x4000 ; are we within 16k of beginning of segment?
jae get_out ; no, get out
add ax, 0x8000 ; yes, add 32k to offset
sub dx, 0x0800 ; sub 0x0800 paragraphs from segment == 32k
get_out:
}
}
/*
* Name: ptoul - pointer to unsigned long
* Purpose: convert a far pointer to unsigned long integer
* Date: June 5, 1991
* Passed: s: string pointer
* Notes: combine the offset and segment like so:
* offset 0000
* segment + 0000
* =======
* 00000
* result is returned in ax:dx
*/
unsigned long ptoul( s )
text_ptr s;
{
_asm {
mov ax, WORD PTR s ; ax = offset of s
mov dx, WORD PTR s+2 ; dx = segment of s
mov bx, dx ; put copy of segment in bx
mov cl, 12 ; cl = decimal 12 - shift hi word 3 digits
shr dx, cl ; convert to 'real segment'
mov cl, 4 ; cl = 4 - shift hi word 1 digit
shl bx, cl ; shift bx - line up on paragraph
add ax, bx ; add low part of segment to offset
adc dx, 0 ; if carry, bump to next 'real' segment
}
}
/*
* Name: addltop - add long to pointer
* Purpose: add long integer to a pointer
* Date: June 5, 1991
* Passed: l: long
* p: text pointer
* Returns: pointer + long integer
* Notes: A long integer takes two WORDs. A far pointer takes two WORDs.
* A long integer cannot be added directly to a far pointer.
* This diagram may help explain better than I can write.
*
* far pointer 0000 offset
* 0xxx segment
* +
* long integer 00000000 -throw away those three
* ====== digits on long integer,
* 0000 offset they have no effect
* new far pointer 0xxx segment
*
* msw = Most Significant WORD
* lsw = Least Significant WORD
*
* When working with the long integer, we don't need to worry about
* the three x's on segment of the pointer. Add or subtract the lsw
* of the long integer to/from the offset. If there is a carry,
* it only affects the left most digit of the msw of the pointer.
*/
text_ptr addltop( l, p )
long l;
text_ptr p;
{
if (l >= 0) {
_asm {
mov ax, WORD PTR p ; ax = offset of p
mov dx, WORD PTR p+2 ; dx = segment of p
mov bx, WORD PTR l+2 ; msw of l in bx
add ax, WORD PTR l ; add lsw of p and lsw of l
adc bx, 0 ; if carry, pointer in another segment
mov cl, 12 ; cl = 12 - shift off 3 digits
shl bx, cl ; only handle 1st part of msw of l
add dx, bx ; add msw of p and msw of l
}
} else {
l = -l; /* convert l to positive and subtract from pointer p */
_asm {
mov ax, WORD PTR p ; ax = offset of p
mov dx, WORD PTR p+2 ; dx = segment of p
mov bx, WORD PTR l+2 ; msw of l in bx
mov cl, 12 ; cl = 12 - shift off 3 digits
sub ax, WORD PTR l ; subtract low part of pointer
adc bx, 0 ; if we borrowed then add it back to bx
shl bx, cl ; only handle 1st digit of msw of l
sub dx, bx ; subtract msw from segment of p
}
}
}
/*
* Name: find_CONTROL_Z - assembler version, see commented C at end
* Purpose: To determine the length of a line up to ^Z
* Date: June 5, 1991
* Passed: s: the line to be measured
* Notes: DOS carried over ^Z to mark the end of files from CP/M. Since
* it is the only character not allowed in regular text files. ^Z
* can be used, instead of '\0', to mark the end of strings. All
* ASCII characters, except ^Z, may be included in a text file.
* However, none of the C string library functions should be used
* when working with text. The string library functions can be used
* on responses solicited from the user.
* Returns: the length of the line
*/
int find_CONTROL_Z( s )
text_ptr s;
{
s = cpf( s );
_asm {
mov dx, ds ; keep ds in dx, MUST save data segment
push si ; put copy of si on stack
xor cx, cx ; cx = 0
mov si, WORD PTR s ; put offset of s in si
mov ax, WORD PTR s+2 ; get segment of s
mov ds, ax ; else, segment in ds
cmp si, 0 ; is offset of s == NULL?
jne not_null ; no, find length
cmp ax, 0 ; is segment of s == NULL?
je get_out ; yes, line length = 0
not_null:
mov bl, CONTROL_Z ; keep Control Z in bl - eos marker
mov ax, si ; pointer is ok, check for word align
shr ax, 1 ; if [si] is odd, lsb is 1 - rotate to carry
jnc top ; see if string is WORD aligned
lodsb ; no, get a BYTE - now WORD aligned
cmp al, bl ; is ds:[si] == ^Z?
je get_out ; yes, have length, cx = 0
inc cx ; increment length variable
ALIGN 2
top:
lodsw ; string is WORD aligned
cmp al, bl ; is lo BYTE == ^Z?
je get_out ; yes, we have length
inc cx ; no, increment counter
cmp ah, bl ; now test higher BYTE, is it ^Z?
je get_out ; yes, we have length
inc cx ; no, increment length
jmp SHORT top ; look at next two characters
get_out:
mov ax, cx ; put length in ax - as defined by Microsoft
mov ds, dx ; get back data segment from dx
pop si ; get back si from stack
}
/*
int len = 0;
while (*s != ^Z) {
++len;
++s;
}
return len;
*/
}
/*
* Name: linelen - assembler version, see commented C at end of routine
* Purpose: To determine the length of a line, up to either a \n or a
* ^Z, whichever comes first.
* Date: June 5, 1991
* Passed: s: the line to be measured
* Notes: Demonstrates 'lodsb' and 'lodsw'. Memory operations are most
* efficient when working with WORDs. See if first BYTE in
* string is WORD aligned. If it is then work with WORDs else
* get the first BYTE and rest of string will be WORD aligned.
* The 'mov' instruction could have been used, but 'lobsb' and
* 'lodsw' automatically increment the memory pointer.
* Returns: the length of the line
*/
int linelen( s )
text_ptr s;
{
s = cpf( s );
_asm {
mov dx, ds ; keep ds in dx, MUST save data segment
push si ; save si on stack
xor cx, cx ; cx = 0
mov si, WORD PTR s ; put offset of s in si
mov ax, WORD PTR s+2 ; get segment of s
mov ds, ax ; else, segment in ds
cmp si, 0 ; is offset of s == NULL?
jne not_null ; no, find length
cmp ax, 0 ; is segment of s == NULL?
je get_out ; yes, line length = 0
not_null:
mov bl, '\n' ; keep new line character in bl
mov bh, CONTROL_Z ; keep Control Z in bh - DOS eof marker
mov ax, si ; pointer is ok, check for word align
shr ax, 1 ; if [si] is odd, lsb is 1 - rotate to carry
jnc top ; see if string is WORD aligned
lodsb ; no, get a BYTE - now WORD aligned
cmp al, bl ; is BYTE == '\n'?
je get_out ; yes, have length, cx = 0
cmp al, bh ; is ds:[si] == ^Z?
je get_out ; yes, have length, cx = 0
inc cx ; increment length variable
ALIGN 2
top:
lodsw ; string is WORD aligned
cmp al, bl ; test lower BYTE, is it '\n'
je get_out ; yes, we have length
cmp al, bh ; no, test for ^Z
je get_out ; yes, we have length
inc cx ; no, increment counter
cmp ah, bl ; now test higher BYTE, is it '\n'
je get_out ; yes, we have length
cmp ah, bh ; is it ^Z
je get_out ; yes, we have length
inc cx ; no, increment length
jmp SHORT top ; look at next two characters
get_out:
mov ax, cx ; put length in ax - as defined by Microsoft
mov ds, dx ; get back data segment from dx
pop si ; get back si from stack
}
/*
int len = 0;
while (*s && *s != '\n') {
++len;
++s;
}
return len;
*/
}
/*
* Name: prelinelen
* Purpose: To determine the length of a line, from the current position
* backwards to either a \n or a ^Z, whichever comes first.
* Date: June 5, 1991
* Passed: s: the line to be measured
* Returns: the length of the line up to the current position
* Notes: It is assumed there will be a "terminating" ^Z before the
* start of the first line.
*/
int prelinelen( s )
text_ptr s;
{
s = cpb( s );
_asm {
push di ; put copy of di on stack
xor ax, ax ; ax = 0, keep string length in ax
mov di, WORD PTR s ; get offset of string
mov dx, WORD PTR s+2 ; get segment of string
mov es, dx ; put segment in es
cmp di, 0 ; is offset of string == NULL?
jne not_null ; no, do string stuff
cmp dx, 0 ; is, segment of string == NULL?
je get_out ; yes, don't do NULL string
not_null:
dec di ; look at previous character
ALWORD: dec di ; get ready to chech for WORD align
mov bl, '\n' ; keep '\n' in bl
mov bh, CONTROL_Z ; keep ^Z in bh
mov dx, di ; pointer is ok, check for WORD align
shr dx, 1 ; if [di] is odd, lsb is 1 - rotate to carry
jnc top ; string is WORD aligned
inc di ; fix the second decrement - see ALWORD
mov dl, BYTE PTR es:[di] ; get a BYTE - put in DL
cmp dl, bl ; is it '\n'
je get_out ; yes, get out - count = 0
cmp dl, bh ; is it ^Z
je get_out ; yes, get out - count = 0
inc ax ; increment length counter
dec di ; pointer was BYTE aligned, dec pointer
dec di ; pointer is now WORD aligned
ALIGN 2
top:
mov dx, WORD PTR es:[di] ; load WORD - hi BYTE is next
cmp dh, bl ; is hi BYTE (next char) '\n'?
je get_out ; yes, get out - count already in ax
cmp dh, bh ; is hi BYTE (next char) ^Z?
je get_out ; yes, get out - count already in ax
inc ax ; increment character counter
cmp dl, bl ; now check lo BYTE, is it '\n'?
je get_out ; yes, get out - count is in ax
cmp dl, bh ; is lo BYTE ^Z?
je get_out ; yes, get out - count is in ax
inc ax ; increment character counter
dec di ; decrement pointer
dec di ; align pointer on WORD
jmp SHORT top ; test next 2 characters
get_out:
pop di ; get back di from stack
}
/*
int len = 0;
while (*--s != CONTROL_Z && *s != '\n')
++len;
return len;
*/
}
/*
* Name: find_next
* Purpose: To find the first character in the next line after the starting
* point.
* Date: June 5, 1991
* Passed: s: the starting point
* Returns: the first character in the next line
* Notes: This function goes faster if machine works with WORDs. See if
* first BYTE in string is WORD aligned. If it is not, get first
* BYTE in string then the rest of string is WORD aligned.
* Code added at end to adjust segment:offset if needed.
*/
text_ptr find_next( s )
text_ptr s;
{
_asm {
push ds ; save ds on stack
push si ; save si on stack
mov si, WORD PTR s ; load offset of s
mov ax, WORD PTR s+2 ; load segment of s
mov ds, ax
cmp si, 0 ; is offset of string == NULL?
jne not_null ; no, do string stuff
cmp ax, 0 ; is segment of string == NULL?
je return_null ; yes, return NULL if string is NULL
not_null:
mov bl, '\n' ; keep '\n' in bl
mov bh, CONTROL_Z ; keep ^Z in bh
mov ax, si ; move offset of si to ax
shr ax, 1 ; shift right into carry flag
jnc top ; is string WORD aligned?
lodsb ; no, get a BYTE
cmp al, bl ; is it '\n'?
je next_even ; yes, si alread incremented by lodsb
cmp al, bh ; is it ^Z?
je return_null ; yes, return NULL
ALIGN 2
top:
lodsw ; string is WORD aligned, get two BYTEs
cmp al, bl ; is next BYTE == '\n'?
je next_odd ; yes, since si inc for WORD (lodsw) - dec di
cmp al, bh ; is next BYTE == ^Z?
je return_null ; yes, return NULL
cmp ah, bl ; is next BYTE in AH == '\n'?
je next_even ; yes, si is OK - return pointer to next BYTE
cmp ah, bh ; is next BYTE in AH == ^Z?
je return_null ; yes, return NULL
jmp SHORT top ; look at next WORD
ALIGN 2
return_null:
xor ax, ax ; clear ax - offset = NULL
xor dx, dx ; clear dx - segment = NULL
jmp SHORT get_out ; return text_ptr in dx:ax - see Microsoft
ALIGN 2
next_odd:
dec si ; 'lodsw' went one BYTE too far - so dec si
next_even:
mov ax, si ; ds:si now points to next line, load ax
mov dx, ds ; load dx with segment of next BYTE
cmp ax, 0xc000 ; are we within 16k of segment?
jb get_out ; no, get out
sub ax, 0x8000 ; yes, subtract 32k from offset
add dx, 0x0800 ; add 0x0800 paragraphs to segment
get_out:
pop si ; get back si from stack
pop ds ; get back ds from stack
}
/*
while (*s && *s != '\n')
++s;
if (*s)
return ++s;
else
return NULL;
*/
}
/*
* Name: find_prev
* Purpose: To find the start of the line before the current line.
* Date: June 5, 1991
* Passed: current: the current line
* Returns: the start if the previous line
* Notes: current must be at the start of the current line to begin with.
* There must be a ^Z preceding the first line.
* This function goes faster if machine works with WORDs. See if
* first BYTE in string is WORD aligned. If it is not, get first
* BYTE in string then the rest of string is WORD aligned.
* The test for '\n' will pass a lot more than the test for
* ^Z. Set up the WORD align stuff first.
* Since we are searching, by WORDs, backwards, the hi BYTE is the
* prev BYTE and the al BYTE is two prev BYTEs (make sense?).
* Code added at end to adjust segment:offset if needed.
*/
text_ptr find_prev( current )
text_ptr current;
{
_asm {
push di ; save di on stack
mov di, WORD PTR current ; load offset of current
DECR1: dec di ; decrement it
mov ax, WORD PTR current+2 ; load segment of current
mov es, ax
cmp di, 0 ; is offset of string == NULL?
jne not_null ; no, do string string stuff
cmp ax, 0 ; is segment of string == NULL?
je return_null ; yes, return NULL if string NULL
not_null:
mov bl, '\n' ; keep '\n' in bl
mov bh, CONTROL_Z ; keep ^Z in bh
mov ax, di ; put copy of offset in ax
shr ax, 1 ; shift right thru carry flag
jnc on_boundary ; if no carry, string is WORD aligned
;
; if we were to dec the pointer twice, it would be WORD aligned with the
; '--current' BYTE in the AH register. if ^Z test fails, might as well
; test the BYTE in the AL register.
;
DECR2: dec di ; dec offset one more so it is WORD aligned
mov ax, WORD PTR es:[di] ; might as well load WORD
cmp ah, bh ; is prev BYTE ^Z?
je return_null ; yes, return NULL
;
; now we are in the for loop - see commented C code at bottom.
; 'on_boundary' is not part of the for loop so jump past it if needed.
;
cmp al, bl ; is prev BYTE '\n'?
je inc_pointer ; yes, increment the pointer and return
cmp al, bh ; is it ^Z?
je inc_pointer ; yes, increment the pointer and return
jmp SHORT for_loop ;no, pointer is now WORD aligned - do for loop
ALIGN 2
;
; the string ended on an odd boundary and the DECR1 has now aligned the
; string on a WORD. if we load a WORD, the '--current' BYTE would be in the
; AL register.
;
on_boundary:
mov ax, WORD PTR es:[di] ; load --current, aligned on WORD
cmp al, bh ; is --current ^Z?
je return_null ; yes, return NULL
;
; now we are in the for loop and string is guaranteed WORD aligned.
; IMPORTANT: there are 2 cases if the test for '\n' or ^Z pass.
; 1) AH passed, so di must be increment twice for '++current'
; 2) AL passed, inc di once for '++current'
;
ALIGN 2
for_loop:
dec di ; decrement di twice so it will be
dec di ; WORD aligned
mov ax, WORD PTR es:[di] ; string is WORD aligned
cmp ah, bl ; is --current '\n'?
je next_even ; yes, increment di twice to return ++current
cmp ah, bh ; is --current ^Z?
je next_even ; yes, increment di twice to return ++current
cmp al, bl ; look at low part of WORD, is it '\n'?
je inc_pointer ; yes, increment di once to return ++current
cmp al, bh ; is low part of WORD ^Z?
je inc_pointer ; yes, increment di once to return ++current
jmp SHORT for_loop ; get next WORD
ALIGN 2
return_null:
xor ax, ax ; clear ax - offset = NULL
xor dx, dx ; clear dx - segment = NULL
jmp SHORT get_out ; return text_ptr in dx:ax - see Microsoft
ALIGN 2
next_even:
inc di ; di is a WORD too far - inc di
inc_pointer:
inc di ; ++current
mov ax, di ; put offset in ax
mov dx, es ; put segment in dx, return dx:ax - Microsoft
cmp ax, 0x4000 ; are we within 16k of segment?
jae get_out ; no, get out
add ax, 0x8000 ; yes, add 32k to offset
sub dx, 0x0800 ; sub 0x0800 paragraphs to segment
get_out:
pop di ; get back di from stack
}
/*
if (*--current == ^Z)
return NULL;
for (;;) {
if (*--current == '\n' || *current == ^Z)
return ++current;
}
*/
}
/*
* Name: update_line
* Purpose: Display the current line in window
* Date: June 5, 1991
* Passed: window: information allowing access to the current window
* Returns: none
* Notes: Show string starting at column zero and if needed blank rest
* of line. Put max_col in cx and count down. When we run into
* '\n', cx contains number of columns to blank out. Use the
* fast 'rep stosw' to clear the end of line.
*/
void update_line( window )
windows *window;
{
text_ptr text; /* current character of orig begin considered */
char far *screen_ptr;
int attr;
int line;
int col;
int bc, ec;
int normal, block;
int max_col;
int block_line;
int len;
int c;
long rline;
file_infos *file;
file = window->file_info;
max_col = g_display.ncols;
line = window->cline;
normal = g_display.text_color;
block = g_display.block_color;
/* 160 = 80 chars + 80 attr for each line */
screen_ptr = g_display.display_address + line * 160;
text = cpf( window->cursor );
bc = window->bcol;
if (bc > 0) {
if ((col = linelen( text )) < bc)
bc = col;
text += bc;
}
rline = window->rline;
if (file->block_type && rline >= file->block_br && rline <= file->block_er)
block_line = TRUE;
else
block_line = FALSE;
if (block_line == TRUE && file->block_type == BLOCK) {
len = linelen( text );
bc = file->block_bc - window->bcol;
ec = file->block_ec - window->bcol;
_asm {
push ds ; MUST save ds - push it on stack
push si ; save si on stack
;
; set up local register variables
;
mov ax, WORD PTR bc ; get beginning column
mov bl, al ; keep it in bl
mov ax, WORD PTR ec ; get ending column
mov bh, al ; keep it in bh
mov ax, WORD PTR normal ; get normal attribute
mov dl, al ; keep it in dl
mov ax, WORD PTR block ; get block attribute
mov dh, al ; keep it in dh
mov ax, WORD PTR max_col ; get max number columns on screen
mov ch, al ; keep it in ch
xor cl, cl ; col = 0, keep col in cl
;
; load screen and text pointer
;
mov di, WORD PTR screen_ptr ; load offset of screen ptr
mov ax, WORD PTR screen_ptr+2 ; load segment of screen ptr
mov es, ax
mov si, WORD PTR text ; load offset of text ptr
mov ax, WORD PTR text+2 ; load segment of text ptr
mov ds, ax ; move segment of text in ds
cmp si, 0 ; is offset of text ptr == NULL?
jne not_null ; no, output string
cmp ax, 0 ; is segment of text ptr == NULL?
je block_eol ; yes, clear end of line
not_null:
ALIGN 2
top:
cmp cl, ch ; is col == max_col 0?
je getout ; yes, thru with line
lodsb ; get next char in string
cmp al, CONTROL_Z ; is it ^Z?
je block_eol ; yes, must check block past ^Z
cmp al, '\n' ; is it '\n'?
je block_eol ; yes, must check block past '\n'
mov ah, dl ; assume normal attribute
cmp cl, bl ; is col < bc? (less than beginning col)
jl ch_out1 ; yes, show char and normal attribute
cmp cl, bh ; is col > ec? (greater than ending col)
jg ch_out1 ; yes, show char and normal attribute
mov ah, dh ; must be in a block - show block attribute
ch_out1:
stosw ; else show char on screen
inc cl ; ++col
jmp SHORT top ; get another character
ALIGN 2
block_eol:
mov al, ' ' ; clear rest of line w/ spaces
b1:
mov ah, dl ; assume normal attribute
cmp cl, bl ; is col < bc? (less than beginning col)
jl ch_out2 ; yes, show char and normal attribute
cmp cl, bh ; is col > ec? (greater than ending col)
jg ch_out2 ; yes, show char and normal attribute
mov ah, dh ; must be in a block - show block attribute
ch_out2:
stosw ; write blank and attribute to screen
inc cl ; ++col
cmp cl, ch ; is col == max_col?
jl b1 ; while less output block
getout:
pop si
pop ds
}
/*
for (col=0; col < max_col; col++) {
attr = normal;
if (col >= bc && col <= ec)
attr = block;
if (col < len)
c = text[col];
else
c = ' ';
update_char( c, col, line, attr );
}
*/
} else {
if (block_line)
attr = block;
else
attr = normal;
_asm {
mov dx, ds ; MUST save ds - keep it in dx
push di ; save di on stack
push si ; save si on stack
mov bx, WORD PTR attr ; keep attribute in bl
mov bh, '\n' ; keep '\n' in bh
mov cx, WORD PTR max_col ; keep max_col in cx
mov di, WORD PTR screen_ptr ; load offset of screen ptr
mov ax, WORD PTR screen_ptr+2 ; load segment of screen ptr
mov es, ax
mov si, WORD PTR text ; load offset of text ptr
mov ax, WORD PTR text+2 ; load segment of text ptr
mov ds, ax ; move segment of text in ds
cmp si, 0 ; is offset of pointer == NULL?
jne nnot_null ; no, output string
cmp ax, 0 ; is segment of pointer == NULL?
je clreol ; yes, then clear rest of line
nnot_null:
mov ah, bl ; get attribute
ALIGN 2
topp:
or cx, cx ; col == 0 ?
je getoutt ; yes, thru with line
lodsb ; get next char in string
cmp al, CONTROL_Z ; is it ^Z
je clreol ; yes, clear end of line
cmp al, bh ; is it '\n'
je clreol ; yes, clear end of line
stosw ; else show char on screen
dec cx ; --col, count down from max_column
jmp SHORT topp ; get another character
ALIGN 2
clreol:
mov ah, bl ; get attribute
mov al, ' ' ; clear eol with ' '
rep stosw ; count is in cx - set rest of line to ' '
getoutt:
pop si
pop di
mov ds, dx
}
}
/*
if (orig != NULL) {
text = orig;
screen_ptr = g_display.display_address + line * 160 + col * 2;
for (; *text != '\n' && *text != ^Z && col < max_col; text++, col++) {
*screen_ptr++ = *text;
*screen_ptr++ = attr;
}
}
if (col < max_col)
eol_clear( col, line, attr );
*/
}
/*
* Name: update_char
* Purpose: diplay one character in window
* Date: June 5, 1991
* Passed: window: information allowing access to the current window
* c: character to output to screen
* col: col to display character
* line: line number to display character
* Returns: none
*/
void update_char( window, c, col, line )
windows *window;
int c, col, line;
{
char far *screen_ptr;
int attr;
long rline;
file_infos *file;
file = window->file_info;
rline = window->rline;
attr = g_display.text_color;
if (file->block_type) {
if (rline >= file->block_br && rline <= file->block_er) {
if (file->block_type == LINE)
attr = g_display.block_color;
else if (window->rcol>=file->block_bc && window->rcol<=file->block_ec)
attr = g_display.block_color;
}
}
screen_ptr = g_display.display_address + line * 160 + col * 2;
_asm {
mov dx, di ; save di in dx
mov di, WORD PTR screen_ptr ; load offset of screen ptr
mov ax, WORD PTR screen_ptr+2 ; load segment of screen ptr
mov es, ax
mov bx, WORD PTR attr ; get attribute
mov ah, bl ; put in ah
mov bx, WORD PTR c ; get character
mov al, bl ; put in al
stosw ; show char on screen
mov di, dx ; get back di from dx
}
/*
screen_ptr = g_display.display_address + line * 160 + col * 2;
*screen_ptr++ = c;
*screen_ptr = attr;
*/
}
/*
* Name: c_output
* Purpose: To make as few changes as possible to cause the current line
* to be what it should be.
* Date: June 5, 1991
* Passed: c: character to output to screen
* col: col to display character
* line: line number to display character
* attr: attribute of character
* Returns: none
*/
void c_output( c, col, line, attr )
int c, col, line, attr;
{
char far *screen_ptr;
screen_ptr = g_display.display_address + line * 160 + col * 2;
_asm {
mov dx, di ; save di in dx
mov di, WORD PTR screen_ptr ; load offset of screen ptr
mov ax, WORD PTR screen_ptr+2 ; load segment of screen ptr
mov es, ax
mov bx, WORD PTR attr ; get attribute
mov ah, bl ; put in ah
mov bx, WORD PTR c ; get character
mov al, bl ; put in al
stosw ; show char on screen
mov di, dx ; get back di from dx
}
/*
screen_ptr = g_display.display_address + line * 160 + col * 2;
*screen_ptr++ = c;
*screen_ptr = attr;
*/
}
/*
* Name: s_output
* Purpose: To output character string at the cursor position, advancing
* the cursor by the length of the string.
* Date: June 5, 1991
* Passed: s: string to output
* Notes: This function is used to output most strings not part of file text.
*/
void s_output( s, line, col, attr )
char *s;
int line, col, attr;
{
text_ptr text; /* current character of orig begin considered */
char far *screen_ptr;
int max_col;
max_col = g_display.ncols;
screen_ptr = g_display.display_address + line * 160 + col * 2;
_asm {
push ds ; MUST save ds
push di ; save di on stack
push si ; save si on stack
mov bx, WORD PTR attr ; keep attribute in bx
mov cx, WORD PTR col ; put cols in cx
mov dx, WORD PTR max_col ; keep max_col in dx
mov di, WORD PTR screen_ptr ; load offset of screen ptr
mov ax, WORD PTR screen_ptr+2 ; load segment of screen ptr
mov es, ax
mov si, WORD PTR s ; load offset of string ptr
or si, si ; is it == NULL?
je getout ; yes, no output needed
mov ax, WORD PTR s+2 ; load segment of string ptr
or ax, ax ; is pointer == NULL?
je getout ; yes, no output needed
mov ds, ax ; load segment of text in ds
mov ah, bl ; put attribute in AH
top:
cmp cx, dx ; col < max_cols?
jge getout ; no, thru with line
lodsb ; get next char in string - put in al
or al, al ; is it '\0'
je getout ; yes, end of string
stosw ; else show attr + char on screen (ah + al)
inc cx ; col++
jmp SHORT top ; get another character
getout:
pop si ; get back si
pop di ; get back di
pop ds ; get back ds
}
/*
screen_ptr = g_display.display_address + line * 160 + col * 2;
max_col = g_display.ncols;
while (*s && col < max) {
*screen_ptr++ = *s++;
*screen_ptr++ = attr;
}
*/
}
/*
* Name: eol_clear
* Purpose: To clear the current line from the cursor to the end of the
* line to normal spaces.
* Date: June 5, 1991
* Notes: Basic assembly - comments should be enough explanation.
*/
void eol_clear( int col, int line, int attr )
{
int max_col;
char far *screen_ptr;
max_col = g_display.ncols;
screen_ptr = g_display.display_address + line * 160 + col * 2;
_asm {
push di ; save di on stack
mov bx, WORD PTR attr ; keep attribute in bx
mov dx, WORD PTR col ; put cols in dx
mov cx, WORD PTR max_col ; put max_col in cx
cmp dx, cx ; max_cols < cols?
jge getout ; no, thru with line
sub cx, dx ; number of column to clear
mov di, WORD PTR screen_ptr ; load offset of screen ptr
mov ax, WORD PTR screen_ptr+2 ; load segment of screen ptr
mov es, ax
mov ah, bl ; get attribute in ah
mov al, ' ' ; store ' ' in al
rep stosw ; clear to end of line
getout:
pop di ; get back di from stack
}
/*
for (; col < g_display.ncols; col++) {
*p++ = ' ';
*p++ = attr;
}
*/
}